home *** CD-ROM | disk | FTP | other *** search
-
- /*******************************************\
- * *
- * simarea.c = Area operations for SIMPP: *
- * Simple IMage Processing Package. *
- * Copyright (c) 1987, Benjamin M. Dawson *
- * Edit Version: 1.1 : Jan-29-87 *
- * *
- \*******************************************/
-
- #include "simpp.h"
-
- extern char *malloc();
-
- /* convolve = Convolve the image area starting at x,y and of size dx,dy
- * with the kernel of size m,n. Scale (divide) the output by scale, and
- * change the sign of the output values according to the output flag.
- */
- int convolve(x,y,dx,dy,m,n,kernel,scale,output)
- int x,y; /* Start of area to convolve */
- int dx,dy; /* Size of area to convolve */
- int m,n; /* Kernel (x,y) size */
- int *kernel; /* Pointer to kernel array */
- int scale; /* Amount to right shift results */
- int output; /* Output flag */
- {
- PIXEL *bp[MAX_KERNEL_SIZE]; /* Input pointers */
- PIXEL *ptemp; /* Temporary pointer */
- register int i,j; /* Loop variables */
- int x_out,y_out; /* output x,y index */
- int xx; /* Offset x address */
- int xend; /* Reduced x size */
- long sum; /* Convolution sum */
- long max_pos; /* Maximum + pixel value */
- long maxs_pos; /* Maximum signed + value */
- long maxs_neg; /* Maximum signed - value */
- int *kp; /* Pointer to kernel */
-
- #ifdef CHECK
- /* Check source and destination ranges */
- if (check_area(x,y,dx,dy,"<convolve>") == ERROR)
- return(ERROR);
- /* Check kernel size */
- if ((m > MAX_KERNEL_SIZE) || (m < 1) ||
- (n > MAX_KERNEL_SIZE) || (n < 1)) {
- printf("<convolution> Kernel size out of range!\n");
- return(ERROR);
- }
- /* Special check against kernel size */
- if ((dx < m) || (dy < n)) {
- printf("<convolution> Area too small!\n");
- return(ERROR);
- }
- #endif
-
- /* Set up long values for output value checking */
- max_pos = (long)MAXPIX;
- maxs_pos = max_pos/2L;
- maxs_neg = -((long)(PIXEL_SIZE/2));
-
- /* Allocate line buffers for input */
- for (i = 0 ; i < n ; i++)
- bp[i] = (PIXEL *)malloc(dx*sizeof(PIXEL));
-
- /* Set up addresses and indices */
- x_out = x + (m/2); /* These factors correct for the convolution */
- y_out = y + (n/2); /* edge effects (see BYTE article) */
- dy -= (n-1); /* Reduce area to account for edge effects */
- xend = dx - m;
-
- /* Read first n lines into the input buffers */
- for (i = 0 ; i < n ; i++) read_hline(x,y++,dx,bp[i]);
-
- /* Main convolution loop */
- while (dy--) { /* Scan down the image */
- for (xx = 0 ; xx <= xend ; xx++) { /* Scan across the image */
- /* Inner loop */
- sum = 0L; /* 0 out convolution sum */
- kp = kernel; /* Set up pointer to kernel */
- for (j = 0 ; j < n ; j++) {
- ptemp = bp[j] + xx; /* Point to line area with pixels */
- for (i = 0 ; i < m ; i++ )
- sum += ((long)*ptemp++)*((long)*kp++);
- }
- /* Scale the output sum quickly with a shift right operation. Unfortunately,
- a shift right some machines fills 0's rather than the sign bit. A ifdef
- selects for these unfortunate machines */
- #ifdef NO_SIGN_FILL
- if (sum < 0) {
- sum = -sum;
- sum >>= (long)scale;
- sum = -sum;
- }
- else sum >>= (long)scale;
- # else
- sum >>= (long)scale;
- #endif
-
- /* Output value modified according to output flag */
- switch(output) {
- case SIGNED: /* Clip values to range from */
- if (sum < maxs_neg) sum = maxs_neg; /* maxs_neg to */
- if (sum > maxs_pos) sum = maxs_pos; /* maxs_pos */
- break;
- case POSITIVE: /* Positive values only. - set to 0 */
- if (sum < 0L) sum = 0L;
- if (sum > max_pos) sum = max_pos;
- break;
- case NEGATIVE: /* Negative only. Sign inverted. */
- if (sum > 0L) sum = 0L;
- sum = - sum;
- if (sum > max_pos) sum = max_pos;
- break;
- case ABSOLUTE: /* Absolute value */
- if (sum < 0L) sum = -sum;
- if (sum > max_pos) sum = max_pos;
- break;
- }
-
- write_pixel(x_out+xx,y_out,(PIXEL)sum); /* Write out value */
- }
- /* Shuffle pointers so that all is in order */
- ptemp = bp[0];
- for (i = 0 ; i < n-1 ; i++) /* Shift buffer pointers */
- bp[i] = bp[i+1];
- bp[n-1] = ptemp;
- /* Replace oldest line with new line, and move down a line */
- read_hline(x,y++,dx,bp[n-1]);
- y_out++;
- }
-
- /* Free buffers */
- for (i = 0 ; i < n ; i++) free(bp[i]);
- return(OK);
- }
-
- /* ================================================================ */
-
- /* label = Label an area. The pixels in the area must be binary with target
- * value == bin1 and background value of bin0. The area is scanned for
- * connected groups of pixels (blobs). If a connected area has more
- * than minpix pixels, it's values are changed to a label. Labels
- * are chosen sequentially starting at blabel and going to elabel, then
- * the label values repeat. The binary values, bin0 and bin1, must NOT
- * be part of the label set!!! Areas less than minpix are "killed" by
- * setting them to bin0. This improves processing speed.
- */
-
- /* Static variables to save stack space */
- static int count = 0; /* Count of pixels in area */
- static PIXEL oldcolor = 0; /* Target color */
- static PIXEL newcolor = 0; /* Label color */
- static int xleft = 0; /* Boundary values */
- static int ytop = 0; /* For checking recursion area */
- static int xright = XSIZE-1;
- static int ybottom = YSIZE-1;
-
- int label(x,y,dx,dy,bin0,bin1,minpix,blabel,elabel)
- int x,y; /* Start of area to label */
- int dx,dy; /* Size of area to label */
- PIXEL bin0; /* Binary 0 value */
- PIXEL bin1; /* Binary 1 value */
- int minpix; /* Minimum number of connected pixels for label */
- PIXEL blabel; /* Begining value to label with */
- PIXEL elabel; /* End value to label with */
- {
- register int i;
- PIXEL lv;
-
- #ifdef CHECK
- /* Check area to scan */
- if (check_area(x,y,dx,dy,"<label>") == ERROR)
- return(ERROR);
- /* Check that the specified labels are not the same as binary values */
- if ((blabel == bin0) || (blabel == bin1) ||
- (elabel == bin0) || (elabel == bin1)) {
- printf("<label> Labels cannot == binary values!!\n");
- return(ERROR);
- }
- #endif
-
- /* Set up boundary values */
- xleft = x;
- ytop = y;
- xright = x+dx-1;
- ybottom = y+dy-1;
- /* Set up label value */
- lv = blabel;
- /* Search area */
- while (dy--) {
- for (i = x ; i < dx+x ; i++) {
- /* If there is a target pixel, fill it */
- if (read_pixel(i,y) == bin1) {
- count = 0; /* Count of pixels */
- oldcolor = bin1;/* Target color */
- newcolor = lv; /* Color to fill with */
- fill_horiz(i,y); /* Fill with value */
- if (count < minpix) { /* Erase if < minpix */
- oldcolor = lv;
- newcolor = bin0;
- fill_horiz(i,y);
- }
- else { /* Bump color */
- if (++lv > elabel) lv = blabel;
- }
- }
- }
- y++;
- }
-
- return(OK);
- }
-
- /* ================================================================ */
-
- /* Recursion/iteration routines for finding and filling connected areas */
-
- static int xl,xr;
-
- /* Horizontal fill recursion. Does most of the work... */
- static VOID fill_horiz(x,y)
- int x,y;
- {
- /* Is this a hit? */
- if (read_pixel(x,y) == oldcolor) {
- /* Change as long a horizontal line as you can. Keep track of x, dx */
- xr = x;
- while (xr <= xright) {
- if (read_pixel(xr,y) == oldcolor) {
- write_pixel(xr++,y,newcolor);
- count++;
- }
- else break;
- }
-
- xl = x-1;
- while (xl >= xleft) {
- if (read_pixel(xl,y) == oldcolor) {
- write_pixel(xl--,y,newcolor);
- count++;
- }
- else break;
- }
- xl++;
- if ((xr-xl) > 0) fill_vert(xl,y,xr-xl);
- }
- }
-
- /* vertical fill recursion */
- static VOID fill_vert(x,y,dx)
- int x,y,dx;
- {
- while(dx--) {
- /* Boundary check and recurse up */
- if (--y >= ytop) fill_horiz(x,y);
- y++;
- /* Boundary check and recurse down (Remember: "Video coordinates") */
- if (++y <= ybottom) fill_horiz(x,y);
- y--;
- x++;
- }
- }
-
- /* ================ End of simarea.c ================ */
-
- /* <-- FILE BREAK --> */